home *** CD-ROM | disk | FTP | other *** search
- char *ckzv = "Amiga file support $Id: ckifio.c,v 1.8 93/08/03 08:28:44 swalton Exp Locker: swalton $";
-
- /* C K I F I O -- Kermit file system support for the Amiga */
-
- /*
- Author: Frank da Cruz (SY.FDC@CU20B),
- Columbia University Center for Computing Activities, January 1985.
- Modified for Amiga by Jack J. Rouse, The Software Distillery
- Further modified for C Kermit version 4F(095) by Stephen Walton,
- California State University, Northridge, ecphssrw@afws.csun.edu
-
- Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
- York. Permission is granted to any individual or institution to use this
- software as long as it is not sold for profit. This copyright notice must be
- retained. This software may not be included in commercial products without
- written permission of Columbia University.
-
- $Log: ckifio.c,v $
- * Revision 1.8 93/08/03 08:28:44 swalton
- * Changed include of SAS and Aztec-specific include files to Amiga
- * standard (clib/ and pragmas/).
- *
- * Revision 1.7 92/10/30 16:11:42 swalton
- * Added code to call SetCurrentDirName() if and only if ROM version
- * is greater than 37. Depends on the extern int v37, set in ckitio.c.
- *
- * Revision 1.6 92/01/15 17:14:16 swalton
- * Delete the Aztec StatToTime function, as it is now identical to the
- * Lattice one.
- *
- * Also used Id rather than Header in the RCS ID string.
- *
- * Revision 1.5 91/07/18 16:01:59 swalton
- * zxcmd() fixed to work properly. I had accidentally copied the first part
- * of the Unix version, which dealt with Kermit sending its received data
- * to a command as its input. Amiga Kermit doesn't support this, but does
- * support sending the output of a command to a remote Kermit via the
- * pipeopen() routine in ckiutl.c.
- *
- * Revision 1.4 91/05/29 09:08:17 swalton
- * 1. Changed function definitions to prototype style. Required adding
- * a few forward declarations.
- * 2. Removed includes of stdio.h, stdlib.h, and string.h, as they are
- * now pulled in by ckcdeb.h, provided we compile with -DCK_ANSILIBS.
- *
- * Revision 1.3 90/11/19 21:46:11 swalton
- * Modifications for compiling with SAS/C Version 5.10, courtesy of
- * Larry Rosenman (ler@lerami.lonestar.org, ler on BIX)
- *
- * Revision 1.2 90/11/07 14:40:57 swalton
- * Version 1.2--released to world as first beta test version simultaneously
- * with release of edit 5A(160).
- *
- * Revision 1.1 90/07/12 07:56:05 swalton
- * Fairly extensive modifications to bring Amiga Kermit up to Version 5A, edit
- * 149. Most of the changes can be discerned by reading ckasys.doc, the C Kermit
- * interface document and looking for the items flagged *NEW*.
- *
- * Revision 1.0 90/04/30 11:54:31 swalton
- * Initial revision
- *
- */
-
- /* Includes */
-
- #define LONG /* Prevent LONG definition from coming from
- ckcdeb.h, as it conflicts with exec/type.h */
- #include "ckcdeb.h" /* Typedefs, formats for debug() */
- #undef LONG
- #include "ckcker.h" /* Kermit definitions */
- #include "ckcfil.h" /* File related symbols. */
- #if AZTEC_C
- #include <stat.h>
- #endif
- #if __SASC
- #include <sys/types.h>
- #include <sys/stat.h>
- #endif
- #include <time.h>
- #include <libraries/dosextens.h>
- #include <exec/memory.h>
-
- #include <clib/exec_protos.h>
- #include <clib/dos_protos.h>
- #include <pragmas/exec_pragmas.h>
- #include <pragmas/dos_pragmas.h>
-
- #include <fcntl.h> /* for prototypes for write() and read() */
- #define MAXNAMLEN 30
- #ifdef AZTEC_C
- char *ckzsys = " Amiga (Aztec C)";
- #endif
- #ifdef __SASC
- char *ckzsys = " Amiga (SAS/C)";
- #endif
-
- /* Definitions of some Amiga system commands */
-
- char *DIRCMD = "list "; /* For directory listing */
- char *DIRCM2 = "list "; /* Also for directory listing. */
- char *DELCMD = "delete "; /* For file deletion */
- char *TYPCMD = "type "; /* For typing a file */
- char *PWDCMD = "cd "; /* For saying where I am */
-
- char *SPACMD = "info ";
-
- char *SPACM2 = "info "; /* should be space in specified directory */
-
- char *WHOCMD = "status "; /* Check process status */
-
- #define MAXWLD 300
-
- /*
- Functions (n is one of the predefined file numbers from ckermi.h):
-
- zopeni(n,name) -- Opens an existing file for input.
- zopeno(n,name,attr,fcb) -- Opens a new file for output.
- zclose(n) -- Closes a file.
- zchin(n,&c) -- Gets the next character from an input file.
- zsinl(n,s,x) -- Reads a line from file number n.
- zsout(n,s) -- Write a null-terminated string to output file, buffered.
- zsoutl(n,s) -- Like zsout, but appends a line terminator.
- zsoutx(n,s,x) -- Write x characters to output file, unbuffered.
- zchout(n,c) -- Add a character to an output file, unbuffered.
- zchki(name) -- Check if named file exists and is readable, return size.
- zchko(name) -- Check if named file can be created.
- zchkspa(fn, len) -- Check if there is enough space for file.
- znewn(name,s) -- Make a new unique file name based on the given name.
- zdelet(name) -- Delete the named file.
- zxpand(string) -- Expands the given wildcard string into a list of files.
- znext(string) -- Returns the next file from the list in "string".
- zxcmd(n,cmd) -- Execute the command in a lower fork on file number n.
- zclosf(n) -- Close input file associated with zxcmd()'s lower fork.
- zrtol(n1,n2) -- Convert remote filename into local form.
- zltor(n1,n2) -- Convert local filename into remote form.
- zstrip(n1, n2) -- Find trailing path component of n1 and return pointer
- zchdir(dirnam) -- Change working directory.
- zhome() -- Return pointer to home directory name string.
- zkself() -- Kill self, log out own job (simply exits)
- zsattr(struct zattr *) -- Return attributes for file which is being sent.
- zstime(f, struct zattr *, x) - Set file creation date from attribute packet.
- zrename(old, new) -- Rename a file.
- zshcmd(s,local) -- Execute a shell command and redirect its output, if
- necessary (see ckasys.doc)
- */
-
- /* Declarations */
-
- FILE *fp[ZNFILS] = { /* File pointers */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
-
- /* (PWP) external def. of things used in buffered file input and output */
- #ifdef DYNAMIC
- extern CHAR *zinbuffer, *zoutbuffer;
- #else
- extern CHAR zinbuffer[], zoutbuffer[];
- #endif /* DYNAMIC */
- extern CHAR *zinptr, *zoutptr;
- extern int zincnt, zoutcnt;
-
- static long iflen = -1; /* Input file length. */
-
- static int fcount; /* Number of files in wild group */
- static char nambuf[MAXNAMLEN+2]; /* Buffer for a filename */
-
- char *mtchs[MAXWLD], /* Matches found for filename */
- **mtchptr; /* Pointer to current match */
- extern short v37; /* Are we 2.0 or greater? */
-
- /* utility functions from ckiutl.c */
- extern int existobj();
- struct DirHandle /* fake structure definition */
- {
- int _foo_;
- };
- extern struct DirHandle *opendir();
- extern char *readdir();
- void closedir();
-
- /*
- * Some new time functions. These are defined up here to make it obvious
- * that they need changing for your compiler.
- */
-
- /*
- * The following uses the fact that, on the Amiga, a tm is a long value
- * containing the number of seconds since midnight January 1, 1970.
- * The Amiga's reference time is January 1, 1978 at midnight.
- * The following conversion value is the number of seconds between
- * those two dates.
- */
- #define CONVERT (86400L*(2*366 + 6*365))
-
- /*
- * TimeToDateStamp accepts a time_t value as returned by, for instance,
- * time() and converts it into an AmigaDos DateStamp.
- */
- static void
- TimeToDateStamp(time_t tm, struct DateStamp *ds) {
- long seconds = (long) tm - CONVERT;
- ds->ds_Days = seconds / 86400;
- ds->ds_Minute = (seconds - (ds->ds_Days * 86400)) / 60;
- ds->ds_Tick = TICKS_PER_SECOND * (seconds%60);
- }
-
- static time_t
- StatToTime(long mtime) {
- return((time_t) (mtime + CONVERT));
- }
-
- /* Z K S E L F -- Kill Self: log out own job, if possible. */
- int
- zkself(void) { /* For "bye", but no guarantee! */
- doexit(GOOD_EXIT, -1);
- }
-
- /* Z O P E N I -- Open an existing file for input. */
- int
- zopeni(int n, char *name) {
- debug(F111," zopeni",name,n);
- debug(F101," fp","",(int) fp[n]);
- if (chkfn(n) != 0) return(0);
- zincnt = 0;
- if (n == ZSYSFN) { /* Input from a system function? */
- /*** Note, this function should not be called with ZSYSFN ***/
- /*** Always call zxcmd() directly, and give it the real file number ***/
- /*** you want to use. ***/
- debug(F110,"zopeni called with ZSYSFN, failing!",name,0);
- *nambuf = '\0'; /* No filename. */
- return(0); /* fail. */
- #ifdef COMMENT
- return(zxcmd(n,name)); /* Try to fork the command */
- #endif
- }
- if (n == ZSTDIO) { /* Standard input? */
- if (isatty(0)) {
- ermsg("Terminal input not allowed");
- debug(F110,"zopeni: attempts input from unredirected stdin","",0);
- return(0);
- }
- fp[ZIFILE] = stdin;
- return(1);
- }
- fp[n] = fopen(name,"r"); /* Real file. */
- debug(F111," zopeni", name, (int) fp[n]);
- if (fp[n] == NULL) perror("zopeni");
- return((fp[n] != NULL) ? 1 : 0);
- }
-
- /* Z O P E N O -- Open a new file for output. */
- int
- zopeno(int n, char *name, struct zattr *zz, struct filinfo *fcb) {
-
- char *p; /* Local use pointer */
- if (fcb) {
- debug(F101,"zopeno fcb disp","",fcb->dsp);
- debug(F101,"zopeno fcb type","",fcb->typ);
- debug(F101,"zopeno fcb char","",fcb->cs);
- } else {
- debug(F100,"zopeno fcb is NULL","",0);
- }
- if (n != ZDFILE)
- debug(F111," zopeno",name,n);
- if (chkfn(n) != 0) return(0);
- if ((n == ZCTERM) || (n == ZSTDIO)) { /* Terminal or standard output */
- fp[ZOFILE] = stdout;
- debug(F101," fp[]=stdout", "", (int) fp[n]);
- zoutcnt = 0;
- zoutptr = zoutbuffer;
- return(1);
- }
- p = "w"; /* Assume write/create mode */
- if (fcb) { /* If called with an FCB... */
- if (fcb->dsp == XYFZ_A) /* Does it say Append? */
- p = "a"; /* Yes. */
- }
- fp[n] = fopen(name,p); /* Open the file */
-
- if (fp[n] == NULL) {
- perror("zopeno can't open");
- } else {
- if (n == ZDFILE) setbuf(fp[n],NULL); /* Debugging file unbuffered */
- }
- zoutcnt = 0; /* (PWP) reset output buffer */
- zoutptr = zoutbuffer;
- if (n != ZDFILE)
- debug(F101, " fp[n]", "", (int) fp[n]);
- return((fp[n] != NULL) ? 1 : 0);
- }
-
- /* Z C L O S E -- Close the given file. */
-
- /* Returns 0 if arg out of range, 1 if successful, -1 if close failed. */
- int
- zclose(int n) {
- int x, x2;
-
- if (chkfn(n) < 1) return(0); /* Check range of n */
-
- if ((n == ZOFILE) && (zoutcnt > 0)) /* (PWP) output leftovers */
- x2 = zoutdump();
- else
- x2 = 0;
-
- x = 0; /* Initialize return code */
- if (fp[ZSYSFN]) { /* If file is realy a pipe */
- x = zclosf(n); /* do it specially */
- } else {
- if ((fp[n] != stdout) && (fp[n] != stdin)) x = fclose(fp[n]);
- fp[n] = NULL;
- }
- iflen = -1; /* Invalidate file length */
- if (x == EOF) /* if we got a close error */
- return (-1);
- else if (x2 < 0) /* or an error flushing the last buffer */
- return (-1); /* then return an error */
- else
- return (1);
- }
-
- /* Z C H I N -- Get a character from the input file. */
-
- /* Returns -1 if EOF, 0 otherwise with character returned in argument */
- int
- zchin(int n, int *c) {
- int a, x;
-
- /* (PWP) Just in case this gets called when it shoudn't */
- if (n == ZIFILE) {
- x = zminchar();
- *c = x;
- return (x);
- }
-
- /* if (chkfn(n) < 1) return(-1); */
- a = getc(fp[n]);
- if (a == EOF) return(-1);
- *c = (CHAR) a & 0377;
- return(0);
- }
-
- /* Z S I N L -- Read a line from a file */
-
- /*
- Writes the line into the address provided by the caller.
- n is the Kermit "channel number".
- Writing terminates when newline is encountered, newline is not copied.
- Writing also terminates upon EOF or if length x is exhausted.
- Returns 0 on success, -1 on EOF or error.
- */
- int
- zsinl(int n, char *s, int x) {
- int z = 0, a;
-
- if (chkfn(n) < 1) { /* Make sure file is open */
- return(-1);
- }
- while (x--) {
- if (zchin(n,&a) < 0) { /* Read a character from the file */
- z = -1;
- break;
- }
- if (a == '\n') break;
- *s = a;
- s++;
- }
- *s = '\0';
- return(z);
- }
-
- /*
- * (PWP) (re)fill the buffered input buffer with data. All file input
- * should go through this routine, usually by calling the zminchar()
- * macro (in ckcker.h).
- */
- int
- zinfill(void) {
- zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
- debug(F101,"zinfill zincnt","",zincnt);
- if (zincnt == 0) return (-1); /* end of file */
- zinptr = zinbuffer; /* set pointer to beginning, (== &zinbuffer[0]) */
- zincnt--; /* one less char in buffer */
- return((int)(*zinptr++) & 0377); /* because we return the first */
- }
-
- /* Z S O U T -- Write a string to the given file, buffered. */
- int
- zsout(int n, char *s) {
- if (chkfn(n) < 1) return(-1);
- fputs(s,fp[n]);
- return(0);
- }
-
- /* Z S O U T L -- Write string to file, with line terminator, buffered */
- int
- zsoutl(int n, char *s) {
- if (chkfn(n) < 1) return(-1);
- fputs(s,fp[n]);
- fputs("\n",fp[n]);
- return(0);
- }
-
- /* Z S O U T X -- Write x characters to file, unbuffered. */
- int
- zsoutx(int n, char *s, int x) {
- if (chkfn(n) < 1) return(-1);
- return(write(fileno(fp[n]),s,x));
- }
-
-
- /* Z C H O U T -- Add a character to the given file. */
-
- /* Should return 0 or greater on success, -1 on failure (e.g. disk full) */
- int
- zchout(int n, char c) {
- if (chkfn(n) < 1) return(-1);
- if (n == ZSFILE)
- return(write(fileno(fp[n]),&c,1)); /* Use unbuffered for session log */
- else { /* Buffered for everything else */
- if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */
- return(ferror(fp[n])?-1:0); /* Check to make sure */
- else /* Otherwise... */
- return(0); /* There was no error. */
- }
- }
-
- /* (PWP) buffered character output routine to speed up file IO */
- int
- zoutdump(void) {
- int x;
- zoutptr = zoutbuffer; /* reset buffer pointer in all cases */
- debug(F101,"zoutdump chars","",zoutcnt);
- if (zoutcnt == 0) { /* nothing to output */
- return(0);
- } else if (zoutcnt < 0) { /* unexpected negative value */
- zoutcnt = 0; /* reset output buffer count */
- return(-1); /* and fail. */
- }
-
- /* Frank Prindle suggested that replacing this fwrite() by an fflush() */
- /* followed by a write() would improve the efficiency, especially when */
- /* writing to stdout. Subsequent tests showed a 5-fold improvement! */
- /* if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) { */
-
- fflush(fp[ZOFILE]);
- if (x = write(fileno(fp[ZOFILE]),zoutbuffer,zoutcnt)) {
- debug(F101,"zoutdump fwrite wrote","",x);
- zoutcnt = 0; /* reset output buffer count */
- return(0); /* things worked OK */
- } else {
- zoutcnt = 0; /* reset output buffer count */
- x = ferror(fp[ZOFILE]); /* get error code */
- debug(F101,"zoutdump fwrite error","",x);
- return(x ? -1 : 0); /* return failure if error */
- }
- }
-
- /* C H K F N -- Internal function to verify file number is ok */
-
- /*
- Returns:
- -1: File number n is out of range
- 0: n is in range, but file is not open
- 1: n in range and file is open
- */
- int
- chkfn(int n) {
- switch (n) {
- case ZCTERM:
- case ZSTDIO:
- case ZIFILE:
- case ZOFILE:
- case ZDFILE:
- case ZTFILE:
- case ZPFILE:
- case ZSFILE:
- case ZSYSFN:
- case ZRFILE:
- case ZWFILE: break;
- default:
- debug(F101,"chkfn: file number out of range","",n);
- fprintf(stderr,"?File number out of range - %d\n",n);
- return(-1);
- }
- return( (fp[n] == NULL) ? 0 : 1 );
- }
-
- /* Z C H K I -- Check if input file exists and is readable */
-
- /*
- Returns:
- >= 0 if the file can be read (returns the size).
- -1 if file doesn't exist or can't be accessed,
- -2 if file exists but is not readable (e.g. a directory file).
- -3 if file exists but protected against read access.
- */
- long
- zchki(char *name) {
- long size, readstat();
-
- size = readstat(name);
- debug(F111,"zchki file size",name,(int)size);
- iflen = size;
- strcpy(nambuf, name); /* Remember file name globally. */
- return(size);
- }
-
- /* Z C H K O -- Check if output file can be created */
-
- /*
- Returns -1 if write permission for the file would be denied, 0 otherwise.
- */
- int
- zchko(char *name) {
- int rc = writestat(name);
-
- #ifdef DEBUG
- if (rc < 0)
- debug(F111,"zchko access failed:",name,rc);
- else
- debug(F111,"zchko access ok:",name,rc);
- #endif
- return(rc);
- }
-
- /* Z D E L E T -- Delete the named file. */
- int
- zdelet(char *name) {
- return(unlink(name));
- }
-
-
- /* Z R T O L -- Convert remote filename into local form */
-
- /* For AMIGA, this means changing uppercase letters to lowercase. */
-
- void
- zrtol(char *name, char *name2) {
- for ( ; *name != '\0'; name++) {
- *name2++ = isupper(*name) ? tolower(*name) : *name;
- }
- *name2 = '\0';
- debug(F110,"zrtol:",name2,0);
- }
-
- /* Z S T R I P -- Strip device & directory name from file specification */
-
- /* Strip pathname from filename "name", return pointer to result in name2 */
-
- static char work[100]; /* buffer for use by zstrip and zltor */
-
- void
- zstrip(char *name, char **name2) {
- char *cp, *pp;
- debug(F110,"zstrip before",name,0);
- pp = work;
- if ((cp = strrchr(name, ':')) == NULL)
- cp = name;
- else
- ++cp;
- for (; *cp != '\0'; cp++) {
- if (*cp == '/')
- pp = work;
- else
- *pp++ = *cp;
- }
- *pp = '\0'; /* Terminate the string */
- *name2 = work;
- debug(F110,"zstrip after",*name2,0);
- }
-
- /* Z L T O R -- Local TO Remote */
-
- /* Convert filename from local format to common (remote) form. */
-
- void
- zltor(char *name, char *name2) {
- char *cp, *pp;
- int dc = 0;
-
- debug(F110,"zltor",name,0);
- pp = work;
- if ((cp = strrchr(name, ':')) == NULL)
- cp = name;
- else
- ++cp;
-
- for (; *cp != '\0'; cp++) { /* strip path name */
- if (*cp == '/') {
- dc = 0;
- pp = work;
- }
- else if (islower(*cp)) *pp++ = toupper(*cp); /* Uppercase letters */
- else if (*cp == '~') *pp++ = 'X'; /* Change tilde to 'X' */
- else if (*cp == '#') *pp++ = 'X'; /* Change number sign to 'X' */
- else if ((*cp == '.') && (++dc > 1)) *pp++ = 'X'; /* & extra dots */
- else *pp++ = *cp;
- }
- *pp = '\0'; /* Tie it off. */
- cp = name2; /* If nothing before dot, */
- if (*work == '.') *cp++ = 'X'; /* insert 'X' */
- strcpy(cp,work);
- debug(F110," name2",name2,0);
- }
-
- /* Z H O M E -- Return pointer to user's home directory */
-
- /* we return "s:", which is where startup scripts are found */
- char *
- zhome(void) {
- return("s:"); /* very approximately */
- }
-
- /* Z C H D I R -- Change directory */
- int
- zchdir(char *dirnam) {
- if (chdir(dirnam) != 0) /* failed */
- return 0;
- if (v37) /* This only if V37 or more */
- if (!SetCurrentDirName(dirnam))
- return 0;
- return 1;
- }
-
- /* Z G T D I R -- Return pointer to user's current directory */
-
- char *
- zgtdir(void) {
-
- #ifdef MAXPATHLEN
- #define CWDBL MAXPATHLEN
- #else
- #define CWDBL 100
- #endif
-
- static char cwdbuf[CWDBL+1];
- char *buf, *getcwd();
- buf = cwdbuf;
- return(getcwd(buf, CWDBL));
- }
-
- /* Z X C M D -- Run a system command so its output can be read like a file */
- int
- zxcmd(int filnum, char *comand) {
- FILE *pipeopen();
- int out;
-
- if (chkfn(filnum) < 0) return(-1); /* Need a valid Kermit file number. */
- if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
- return(0);
-
- out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
-
- /* Output to a command */
-
- if (out) { /* Need popen() to do this. */
- return -1; /* Not yet supported. */
- }
-
- /* Input from a command */
- else {
- if ((fp[filnum] = pipeopen(comand)) == NULL) return -1;
- fp[ZSYSFN] = fp[filnum]; /* Remember */
- zincnt = 0; /* (PWP) reset input buffer */
- zinptr = zinbuffer;
- }
- return 1;
- }
-
- /* Z C L O S F - wait for the child fork to terminate and close the pipe. */
- int
- zclosf(int filnum) {
- pipeclose(fp[filnum]);
- fp[filnum] = fp[ZSYSFN] = NULL;
- return(1);
- }
-
- /* Z X P A N D -- Expand a wildcard string into an array of strings */
- /*
- Returns the number of files that match fn1, with data structures set up
- so that first file (if any) will be returned by the next znext() call.
- */
- int
- zxpand(char *fn) {
- fcount = fgen(fn,mtchs,MAXWLD); /* Look up the file. */
- if (fcount > 0) {
- mtchptr = mtchs; /* Save pointer for next. */
- }
- debug(F111,"zxpand",mtchs[0],fcount);
- return(fcount);
- }
-
-
- /* Z N E X T -- Get name of next file from list created by zxpand(). */
- /*
- Returns >0 if there's another file, with its name copied into the arg string,
- or 0 if no more files in list.
- */
- int
- znext(char *fn) {
- if (fcount-- > 0) strcpy(fn,*mtchptr++);
- else *fn = '\0';
- debug(F111,"znext",fn,fcount+1);
- return(fcount+1);
- }
-
- /* Z C H K S P A -- Check to see if there is enough space for the file. */
-
- /*
- * Uses Manx-supplied dospacket() routine. (Source supplied for SAS/C
- * by Larry Rosenman)
- */
- int
- zchkspa(char *fn, long len) {
- struct MsgPort *MyPort;
- struct InfoData *MyInfo;
- long space;
-
- if ((MyPort = (struct MsgPort *)DeviceProc(fn)) == NULL)
- return -1;
- if ((MyInfo = AllocMem(sizeof(struct InfoData), MEMF_PUBLIC)) == NULL)
- return -1;
- if (dos_packet(MyPort, ACTION_DISK_INFO, ((BPTR) MyInfo) >> 2,
- 0L, 0L, 0L, 0L, 0L) != 0) {
- if (MyInfo->id_UnitNumber == -1) /* Imperfect check for RAM: */
- space = len + 1; /* Always enough space */
- else
- space = (MyInfo->id_NumBlocks - MyInfo->id_NumBlocksUsed)*
- MyInfo->id_BytesPerBlock;
- } else
- space = -1; /* To mark error return after FreeMem(). */
- FreeMem(MyInfo, sizeof(struct InfoData));
- if (space <= 0)
- return -1;
- else if (len < space)
- return 1;
- else
- return 0;
- }
-
- /* Z N E W N -- Make a new name for the given file */
-
- void
- znewn(char *fn,char **s) {
- static char buf[100];
- char *bp;
- int len = 0, d;
- #ifdef MAXNAMLEN
- int maxlen = MAXNAMLEN;
- #else
- int maxlen = 14;
- #endif
-
- bp = buf;
- while (*fn) { /* Copy name into buf */
- *bp++ = *fn++;
- len++;
- }
- if (len > maxlen-3) bp -= 3; /* Don't let it get too long */
-
- /*
- * On the Amiga, it takes much less time to determine
- * if a given file exists than to read all the file names in
- * a directory (or even just names with a certain prefix).
- */
- d = 0;
- do {
- sprintf(bp, "~%d", ++d);
- } while (zchki(buf) != -1 && d < 100);
-
- *s = buf;
- }
-
- /* Z S A T T R */
- /*
- Fills in a Kermit file attribute structure for the file which is to be sent.
- Returns 0 on success with the structure filled in, or -1 on failure.
- If any string member is null, then it should be ignored.
- If any numeric member is -1, then it should be ignored.
- */
- int
- zsattr(struct zattr *xx) {
- long k;
- char *zfcdat();
-
- k = iflen % 1024L; /* File length in K */
- if (k != 0L) k = 1L;
- xx->lengthk = (iflen / 1024L) + k;
- xx->type.len = 0; /* File type can't be filled in here */
- xx->type.val = "";
- if (*nambuf) {
- xx->date.val = zfcdat(nambuf); /* File creation date */
- xx->date.len = strlen(xx->date.val);
- } else {
- xx->date.len = 0;
- xx->date.val = "";
- }
- xx->creator.len = 0; /* File creator */
- xx->creator.val = "";
- xx->account.len = 0; /* File account */
- xx->account.val = "";
- xx->area.len = 0; /* File area */
- xx->area.val = "";
- xx->passwd.len = 0; /* Area password */
- xx->passwd.val = "";
- xx->blksize = -1L; /* File blocksize */
- xx->access.len = 0; /* File access */
- xx->access.val = "";
- xx->encoding.len = 0; /* Transfer syntax */
- xx->encoding.val = 0;
- xx->disp.len = 0; /* Disposition upon arrival */
- xx->disp.val = "";
- xx->lprotect.len = 0; /* Local protection */
- xx->lprotect.val = "";
- xx->gprotect.len = 0; /* Generic protection */
- xx->gprotect.val = "";
- xx->systemid.len = 2; /* System ID length */
- xx->systemid.val = "L3"; /* Amiga system ID code */
- xx->recfm.len = 0; /* Record format */
- xx->recfm.val = "";
- xx->sysparam.len = 0; /* System-dependent parameters */
- xx->sysparam.val = "";
- xx->length = iflen; /* Length */
- return(0);
- }
-
- /* Z F C D A T -- Return a string containing the time stamp for a file */
-
- char *
- zfcdat(char *name) {
-
- struct stat buffer;
- struct tm *time_stamp, *localtime();
- time_t filetime;
- static char datbuf[20];
-
- datbuf[0] = '\0';
- if(stat(name,&buffer) != 0) {
- debug(F110,"zcfdat stat failed",name,0);
- return("");
- }
- filetime = StatToTime(buffer.st_mtime);
- time_stamp = localtime(&filetime);
- if (time_stamp->tm_year < 1900) time_stamp->tm_year += 1900;
- sprintf(datbuf,"%-4.4d%02.2d%02.2d %002.2d:%002.2d:%002.2d",
- time_stamp->tm_year,
- time_stamp->tm_mon + 1,
- time_stamp->tm_mday,
- time_stamp->tm_hour,
- time_stamp->tm_min,
- time_stamp->tm_sec);
- debug(F111,"zcfdat",datbuf,strlen(datbuf));
- return(datbuf);
- }
-
- /* Z S T I M E -- Set creation date for incoming file */
- /*
- Call with:
- f = pointer to name of existing file.
- yy = pointer to a Kermit file attribute structure in which yy->date.val
- is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00.
- x = is a function code: 0 means to set the file's creation date as given.
- 1 means compare the given date with the file creation date.
- Returns:
- -1 on any kind of error.
- 0 if x is 0 and the file date was set successfully.
- 0 if x is 1 and date from attribute structure <= file creation date.
- 1 if x is 1 and date from attribute structure > file creation date.
- */
- int
- zstime(char *f, struct zattr *yy, int x) {
-
- /*
- * This code takes advantage of the ANSI time functions. Once UNIX has
- * an ANSI compiler, maybe UNIX can use this one instead...
- */
-
- struct tm InTime;
- time_t CompareTime;
- struct stat MyStat;
-
- int isleapyear, i;
- static int monthdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
- debug(F110,"zstime",f,0);
-
- if (sscanf(yy->date.val, "%4d%2d%2d %2d:%2d:%2d", &InTime.tm_year,
- &InTime.tm_mon, &InTime.tm_mday, &InTime.tm_hour,
- &InTime.tm_min, &InTime.tm_sec) != 6) {
- debug(F111, "Bad creation date ", yy->date.val, yy->date.len);
- return -1;
- }
- InTime.tm_mon--; /* a struct tm contains months with 0 = Jan */
-
- isleapyear = (( InTime.tm_year % 4 == 0 && InTime.tm_year % 100 !=0) ||
- InTime.tm_year % 400 == 0);
- InTime.tm_year -= 1900;
- /*
- * Find number of days since start-of-year.
- */
- InTime.tm_yday = (isleapyear ? 0 : 1);
- for (i = 0; i <= InTime.tm_mon; i++)
- /* InTime.tm_yday += monthdays[0]; */ /*ler*/
- InTime.tm_yday += monthdays[i];
- InTime.tm_yday += InTime.tm_mday;
- InTime.tm_isdst = 0; /* No daylight savings on Amiga. */
- /*
- * We don't set day-of-week in this code, and simply hope mktime ignores it.
- */
- CompareTime = mktime(&InTime);
- if (x == 1) { /* Compare time with file */
- if (stat(f, &MyStat) < 0) {
- debug(F110,"zstime: stat failed", f, 0);
- return -1;
- }
- if (StatToTime(MyStat.st_mtime) <= CompareTime)
- return 0;
- else
- return 1;
- } else if (x == 0) { /* Set file to time */
- struct DateStamp NewTime;
-
- TimeToDateStamp(CompareTime, &NewTime);
- return(touch(f, &NewTime));
- }
- return -1; /* Illegal value for x */
- }
- /*
- * Set modification date of file fn to NewTime.
- */
- static int
- touch(char *fn, struct DateStamp *NewTime) {
- struct MsgPort *task;
- BPTR lock, plock;
- UBYTE *pointer;
-
- if(!(pointer = (UBYTE *)AllocMem(256L,MEMF_PUBLIC)))
- return -1;
- if(!(task=(struct MsgPort *)DeviceProc(fn))) {
- FreeMem((void *) pointer, 256L);
- return;
- }
- if(!(lock = Lock(fn,SHARED_LOCK))) {
- FreeMem((void *) pointer, 256L);
- return -1;
- }
- plock = ParentDir(lock);
- UnLock(lock);
-
- strcpy((char *)(pointer + 1),fn);
- *pointer = strlen(fn);
-
- dos_packet(task, ACTION_SET_DATE, NULL, plock, (ULONG) &pointer[0] >> 2,
- (ULONG) NewTime, 0L, 0L, 0L);
-
- UnLock(plock);
- FreeMem((void *) pointer, 256L);
- return 0;
- }
- /*
- * Dummy functions for the Amiga. Sending mail cannot be done; I haven't
- * decided how to handle print requests yet.
- */
- int
- zmail(char *p, char *f) { /* Send file f as mail to address p */
- return(0);
- }
-
- int
- zprint(char *p, char *f) { /* Print file f with flags p */
- return(0);
- }
-
- int
- zrename(char *old, char *new) {
- return(rename(old, new) == 0 ? 0 : -1);
- }
-
- /* Z S H C M D -- Issue shell command and redirect output, if necessary. */
-
- /*
- * This function is to pass the command contained in the string s to the
- * local command parser. If the command does not begin with the character
- * ">", then give the command to the system and display its results on the
- * screen. If the command does not begin with ">" and local != 0, then send
- * the results of the command out the currently open communications device.
- *
- * In this version, we simply punt.
- */
- int
- zshcmd(char *s) {
- if (*s == '>') s++;
- return(system(s));
- }
-
- /* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */
-
- /*
- * The path structure is used to represent the name to match.
- * Each slash-separated segment of the name is kept in one
- * such structure, and they are linked together, to make
- * traversing the name easier.
- */
-
- struct path {
- char npart[MAXNAMLEN]; /* name part of path segment */
- struct path *fwd; /* forward ptr */
- };
-
- #define SSPACE 4000 /* size of string-generating buffer */
-
- static char sspace[SSPACE]; /* buffer to generate names in */
- static char *freeptr,**resptr; /* copies of caller's arguments */
- static int remlen; /* remaining length in caller's array*/
- static int numfnd; /* number of matches found */
-
- /*
- * splitpath:
- * takes a string and splits the slash-separated portions into
- * a list of path structures. Returns the head of the list. The
- * structures are allocated by malloc, so they must be freed.
- * Splitpath is used internally by the filename generator.
- *
- * Input: A string.
- * Returns: A linked list of the slash-separated segments of the input.
- */
-
- struct path *
- splitpath(char *p) {
- struct path *head,*cur,*prv;
- int i;
- head = prv = NULL;
- if (*p == '/') p++; /* skip leading slash */
- while (*p != '\0')
- {
- cur = (struct path *) malloc(sizeof (struct path));
- debug(F101,"splitpath malloc","",(cur == NULL ? 0 : 1));
- if (cur == NULL) fatal("malloc fails in splitpath()");
- cur -> fwd = NULL;
- if (head == NULL) head = cur;
- else prv -> fwd = cur; /* link into chain */
- prv = cur;
- for (i=0; i < MAXNAMLEN && *p != '/' && *p != '\0'; i++)
- cur -> npart[i] = *p++;
- cur -> npart[i] = '\0'; /* end this segment */
- if (i >= MAXNAMLEN) while (*p != '/' && *p != '\0') p++;
- if (*p == '/') p++;
- }
- return(head);
- }
-
- /*
- * fgen:
- * This is the actual name generator. It is passed a string,
- * possibly containing wildcards, and an array of character pointers.
- * It finds all the matching filenames and stores them into the array.
- * The returned strings are allocated from a static buffer local to
- * this module (so the caller doesn't have to worry about deallocating
- * them); this means that successive calls to fgen will wipe out
- * the results of previous calls. This isn't a problem here
- * because we process one wildcard string at a time.
- *
- * Input: a wildcard string, an array to write names to, the
- * length of the array.
- * Returns: the number of matches. The array is filled with filenames
- * that matched the pattern. If there wasn't enough room in the
- * array, -1 is returned.
- * By: Jeff Damens, CUCCA, 1984.
- */
- int
- fgen(char *pat, char *resarry[], int len) {
- struct path *head;
- char scratch[100],*sptr;
- char *tail;
- void traverse(struct path *pl, char *sofar, char *endcur);
-
- if ((tail = strrchr(pat, ':')) == NULL) /* locate unit name */
- tail = pat; /* no unit name */
- else
- ++tail; /* eat ':' */
- while (*tail == '/') /* eat parent path slashes */
- ++tail;
- sptr = scratch; /* init buffer correctly */
- while (pat < tail)
- *sptr++ = *pat++;
- head = splitpath(pat);
- numfnd = 0; /* none found yet */
- freeptr = sspace; /* this is where matches are copied */
- resptr = resarry; /* static copies of these so*/
- remlen = len; /* recursive calls can alter them */
- traverse(head,scratch,sptr); /* go walk the directory tree */
- while (head != NULL) {
- struct path *next = head -> fwd;
- free(head); /* return the path segments */
- head = next;
- }
- return(numfnd); /* and return the number of matches */
- }
-
- /* traverse:
- * Walks the directory tree looking for matches to its arguments.
- * The algorithm is, briefly:
- * If the current pattern segment contains no wildcards, that
- * segment is added to what we already have. If the name so far
- * exists, we call ourselves recursively with the next segment
- * in the pattern string; otherwise, we just return.
- *
- * If the current pattern segment contains wildcards, we open the name
- * we've accumulated so far (assuming it is really a directory), then read
- * each filename in it, and, if it matches the wildcard pattern segment, add
- * that filename to what we have so far and call ourselves recursively on the
- * next segment.
- *
- * Finally, when no more pattern segments remain, we add what's accumulated
- * so far to the result array and increment the number of matches.
- *
- * Input: a pattern path list (as generated by splitpath), a string
- * pointer that points to what we've traversed so far (this
- * can be initialized to "/" to start the search at the root
- * directory, or to "./" to start the search at the current
- * directory), and a string pointer to the end of the string
- * in the previous argument.
- * Returns: nothing.
- */
- void
- traverse(struct path *pl, char *sofar, char *endcur) {
- struct DirHandle *fd;
- char *fname;
-
- if (pl == NULL)
- {
- *--endcur = '\0'; /* end string, overwrite trailing / */
- addresult(sofar);
- return;
- }
- if (!iswild(pl -> npart))
- {
- strcpy(endcur,pl -> npart);
- endcur += strlen(pl -> npart);
- *endcur = '\0'; /* end current string */
- if (existobj(sofar)) /* if current piece exists */
- {
- *endcur++ = '/'; /* add slash to end */
- *endcur = '\0'; /* and end the string */
- traverse(pl -> fwd,sofar,endcur);
- }
- return;
- }
- /* cont'd... */
-
- /*...traverse, cont'd */
-
- /* segment contains wildcards, have to search directory */
- *endcur = '\0'; /* end current string */
- if ((fd = opendir(sofar)) == NULL) return; /* can't open, forget it */
- while (fname = readdir(fd))
- {
- if (match(pl -> npart,fname)) {
- char *eos;
- strcpy(endcur,fname);
- eos = endcur + strlen(fname);
- *eos = '/'; /* end this segment */
- traverse(pl -> fwd,sofar,eos+1);
- }
- }
- closedir(fd);
- }
-
- /*
- * addresult:
- * Adds a result string to the result array. Increments the number
- * of matches found, copies the found string into our string
- * buffer, and puts a pointer to the buffer into the caller's result
- * array. Our free buffer pointer is updated. If there is no
- * more room in the caller's array, the number of matches is set to -1.
- * Input: a result string.
- * Returns: nothing.
- */
- int
- addresult(char *str) {
- int l;
- if (--remlen < 0) {
- numfnd = -1;
- return;
- }
- l = strlen(str) + 1; /* size this will take up */
- if ((freeptr + l) > &sspace[SSPACE]) {
- numfnd = -1; /* do not record if not enough space */
- return;
- }
- strcpy(freeptr,str);
- *resptr++ = freeptr;
- freeptr += l;
- numfnd++;
- }
-
- int
- iswild(char *str) {
- char c;
- while ((c = *str++) != '\0')
- if (c == '*' || c == '?') return(1);
- return(0);
- }
-
- #ifdef OLDMATCH
- /*
- * match:
- * pattern matcher. Takes a string and a pattern possibly containing
- * the wildcard characters '*' and '?'. Returns true if the pattern
- * matches the string, false otherwise.
- * by: Jeff Damens, CUCCA
- *
- * Input: a string and a wildcard pattern.
- * Returns: 1 if match, 0 if no match.
- */
- int
- match(char *pattern, char *string) {
- char *psave,*ssave; /* back up pointers for failure */
- psave = ssave = NULL;
- while (1) {
- for (;
- tolower(*pattern) == tolower(*string);
- pattern++,string++) /* skip first */
- if (*string == '\0') return(1); /* end of strings, succeed */
- if (*string != '\0' && *pattern == '?') {
- pattern++; /* '?', let it match */
- string++;
- } else if (*pattern == '*') { /* '*' ... */
- psave = ++pattern; /* remember where we saw it */
- ssave = string; /* let it match 0 chars */
- } else if (ssave != NULL && *ssave != '\0') { /* if not at end */
- /* ...have seen a star */
- string = ++ssave; /* skip 1 char from string */
- pattern = psave; /* and back up pattern */
- } else return(0); /* otherwise just fail */
- }
- }
- #else
- /*
- * match -- match wildcard pattern to string
- * allows multiple '*'s and works without backtracking
- * upper and lower case considered equivalent
- * written by Jack Rouse
- * working without backtracking is cute, but is this usually going
- * to be the most efficient method?
- */
- int
- match(char *pattern, char *target) {
- int link[MAXNAMLEN]; /* list of matches to try in pattern */
- register int first, last; /* first and last items in list */
- register int here, next; /* current and next list items */
- char lowch; /* current target character */
-
- /* start out trying to match at first position */
- first = last = 0;
- link[0] = -1;
-
- /* go through the target */
- for (; *target; ++target)
- {
- /* get lowercase target character */
- lowch = tolower(*target);
-
- /* go through all positions this round and build next round */
- last = next = -1;
- for (here = first; here >= 0; here = next)
- {
- next = link[here];
- switch (pattern[here])
- {
- case '*':
- /* try match at here+1 this round */
- /*!!!check needed only if "**" allowed? */
- if (next != here + 1)
- {
- link[here + 1] = next;
- next = here + 1;
- }
- /* retry match at here next round */
- break;
- default:
- if (tolower(pattern[here]) != lowch)
- continue;
- /* matched, fall through */
- case '?':
- /* try match at here+1 next round */
- ++here;
- break;
- }
- /* try match at here value next round */
- if (last < 0)
- first = here;
- else
- link[last] = here;
- last = here;
- }
- /* if no positions left, match failed */
- if (last == -1) return(0);
- /* terminate list */
- link[last] = -1;
- }
-
- /* at end of target, skip empty matches */
- while (pattern[last] == '*')
- ++last;
-
- return(pattern[last] == '\0');
- }
- #endif
-